#include "line.h"
#include "point.h"
#include "colormanager.h"
#include <QDebug>
#include <cmath>

Line::Line(Point *start, QGraphicsItem *parent, QGraphicsScene *scene, qreal width) :
    QGraphicsLineItem(QLineF(start->rect().center(), start->rect().center()),
        parent, scene), state(commons::DEFAULT), PAD(10)
{
    startPoint = start;
    endPoint = NULL;
    this->setPen(QPen(Qt::red, width));
    this->setZValue(-1);

    left = new QGraphicsLineItem(this, scene);
    right = new QGraphicsLineItem(this, scene);
    top = new QGraphicsLineItem(this, scene);
    bottom = new QGraphicsLineItem(this, scene);
    setBoundingRectVisibility(false);

    setAcceptHoverEvents(true);
    setEnabled(true);
}

Line::Line(const Line &l) :
    QGraphicsLineItem(l.line(), l.parentItem(), l.scene()), state(l.state),
    PAD(l.PAD), startPoint(l.startPoint), endPoint(l.endPoint),
    endDummyPoint(l.endDummyPoint)
{
    this->setPen(l.pen());
    this->setZValue(l.zValue());

    left = new QGraphicsLineItem(this, scene());
    right = new QGraphicsLineItem(this, scene());
    top = new QGraphicsLineItem(this, scene());
    bottom = new QGraphicsLineItem(this, scene());
    setBoundingRectVisibility(false);

    setAcceptHoverEvents(l.acceptHoverEvents());
    setEnabled(l.isEnabled());
    setColor(l.pen().color());
}

Line::~Line()
{
    scene()->removeItem(left);
    scene()->removeItem(right);
    scene()->removeItem(top);
    scene()->removeItem(bottom);
    scene()->removeItem(this);
    delete left;
    delete right;
    delete top;
    delete bottom;
}

void Line::setColor(const QColor &color)
{
    setPen(QPen(QBrush(color), pen().width()));
}

QColor Line::getColor()
{
    return pen().brush().color();
}

void Line::setDestnation(Point *point)
{
    setPen(QPen(QBrush(ColorManager::randomLineColor()), pen().width()));
    setEndPoint(point);
}

void Line::setStartPoint(Point *point)
{
    startPoint = point;
    update();
}

void Line::setEndPoint(Point *point)
{
    endPoint = point;
    update();
}

void Line::setDestnation(const QPoint &point)
{
    endDummyPoint = point;
    update();
}

void Line::update()
{
    if (endPoint != NULL)
        setLine(QLineF(startPoint->rect().center(), endPoint->rect().center()));
    else
        setLine(QLineF(startPoint->rect().center(), QPointF(endDummyPoint)));
    updateBoundingRect();

    if (parentItem()!=NULL)
        parentItem()->update();
}

void Line::updateBoundingRect()
{
    QPointF start = startPoint->rect().center();
    QPointF end = endPoint==NULL ? endDummyPoint : endPoint->rect().center();
    double dx = double(end.x())-start.x();
    double dy = double(end.y())-start.y();
    if (abs(dx)<2*PAD && abs(dy)<2*PAD)
        return;
    double angle = atan(dy / dx);
    double degree = angle * 180 / PI;
//    qDebug() << "angle " << angle;
//    qDebug() << dx << ":" << dy;
//    qDebug() << start << ":" << end;

    left->setLine(start.x(), start.y()-PAD, start.x(), start.y()+PAD);
    left->setTransform(QTransform().translate(start.x(), start.y()).
                       rotate(degree).translate(-start.x(),-start.y()));
    right->setLine(end.x(), end.y()-PAD, end.x(), end.y()+PAD);
    right->setTransform(QTransform().translate(end.x(), end.y()).
                       rotate(degree).translate(-end.x(),-end.y()));

//    QPoint mid = (start + end)/2;

    top->setLine(start.x(), start.y(), end.x(), end.y());
    top->setTransform(QTransform().translate(PAD*sin(angle),-PAD*cos(angle)));
    bottom->setLine(start.x(), start.y(), end.x(), end.y());
    bottom->setTransform(QTransform().translate(-PAD*sin(angle),PAD*cos(angle)));

}

void Line::setBoundingRectVisibility(bool visible)
{

    left->setVisible(visible);
    right->setVisible(visible);
    top->setVisible(visible);
    bottom->setVisible(visible);
}

void Line::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
    if (state == commons::LINE  || state == commons::PLAYING)
    {
        setBoundingRectVisibility(true);
        this->parentItem()->update();
        emit hoverEntered();
    }
}

void Line::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{

    if (state == commons::LINE  || state == commons::PLAYING)
    {
        setBoundingRectVisibility(false);
        this->parentItem()->update();
        emit hoverLeft();
    }
}

void Line::mousePressEvent(QGraphicsSceneMouseEvent *event)
{

    if (event->button() == Qt::RightButton)
        return;

    if (state == commons::LINE_DRAWING)
        // A new line is being drawn starting at this line's start-point or
        // end-point. Ignore press event so that this line's parent canvas
        // can grab press event;
    {
        event->ignore();
    }
    else if (state == commons::LINE || state == commons::PLAYING)
        // Select this line under LINER mode.
    {
        prevState = state;
        state = commons::LINE_MOVING;
        toStartPoint = event->pos() - line().p1();
        toEndPoint = event->pos() - line().p2();
        emit dragStart(this);
//        event->ignore();
    }
}

void Line::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    if (state == commons::LINE_MOVING)
    {
        state = prevState;
        emit dragStop(this);
    } else if (state == commons::LINE)
    {
        emit deleteLine(this);
    }
}

void Line::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    if (state == commons::LINE_MOVING)
    {
        setLine(QLineF(event->pos()-toStartPoint, event->pos()-toEndPoint));
        if (endPoint != NULL)
            endPoint->moveTo(event->pos()-toEndPoint);
        else endDummyPoint = event->pos()-toEndPoint;
        startPoint->moveTo(event->pos()-toStartPoint);
        updateBoundingRect();
        emit lineMoved(this);
        this->parentItem()->update();
    }
}

void Line::detatchStartPoint()
{
    if (endPoint == NULL)
        return;
    endDummyPoint = startPoint->rect().center();
    startPoint = endPoint;
    endPoint = NULL;
    setColor(Qt::red);
}

void Line::detatchEndPoint()
{
    if (endPoint == NULL)
        return;
    endDummyPoint = endPoint->rect().center();
    endPoint = NULL;
    setColor(Qt::red);
}
